/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.echarts.builder.impl;

import cn.easyplatform.web.ext.ComponentHandler;
import cn.easyplatform.web.ext.echarts.ECharts;
import cn.easyplatform.web.ext.echarts.lib.Option;
import com.google.gson.JsonArray;
import java.util.*;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class GraphChartsBuilder extends AbstractChartsBuilder {

    private static final boolean DEBUG = false;

    //private static final List<Object[]> mUserData = new ArrayList<>();
    //private static final List<Object[]> mRelativeData = new ArrayList<>();
    private static final List<List<Object>> mData = new ArrayList<>();
    private List<String> typeList;

    /*static {
        mUserData.add(new Object[]{"王经理", "项目经理", 100, "#ABCDEF"});
        mUserData.add(new Object[]{"李经理", "产品经理", 100, "#FF6666"});
        mUserData.add(new Object[]{"刘经理", "市场经理", 100, "#003366"});
        mUserData.add(new Object[]{"张主管", "项目主管", 100, "#FFCC99"});
        mUserData.add(new Object[]{"陈总监", "技术总监", 120, "#99CCFF"});
        mUserData.add(new Object[]{"李总监", "产品总监", 120, "#99CC33"});
        mUserData.add(new Object[]{"小周", "软件工程师", 80, "#FF9933"});
        mUserData.add(new Object[]{"小卓", "软件工程师", 80, "#CCCC33"});
        mUserData.add(new Object[]{"小王", "软件工程师", 80, "#99CCFF"});
        mUserData.add(new Object[]{"小叶", "后端工程师", 80, "#993399"});
        mUserData.add(new Object[]{"小沈", "前端工程师", 80, "#CCCCCC"});

        mRelativeData.add(new Object[]{"小叶", "小沈", "同事", 2});
        mRelativeData.add(new Object[]{"小王", "小沈", "同事", 2});
        mRelativeData.add(new Object[]{"张主管", "刘经理", "下属", 5});
        mRelativeData.add(new Object[]{"张主管", "王经理", "下属", 5});
        mRelativeData.add(new Object[]{"李总监", "刘经理", "领导", 5});
        mRelativeData.add(new Object[]{"李总监", "张主管", "领导", 5});
        mRelativeData.add(new Object[]{"李总监", "李经理", "领导", 5});
        mRelativeData.add(new Object[]{"李总监", "王经理", "领导", 5});
        mRelativeData.add(new Object[]{"李经理", "小叶", "管理", 2});
        mRelativeData.add(new Object[]{"王经理", "小卓", "管理", 2});
        mRelativeData.add(new Object[]{"王经理", "小周", "管理", 2});
        mRelativeData.add(new Object[]{"王经理", "小王", "管理", 2});
        mRelativeData.add(new Object[]{"陈总监", "李总监", "同事", 8});
        mRelativeData.add(new Object[]{"陈总监", "王经理", "路人", 8});
        mRelativeData.add(new Object[]{"王经理", "陈总监", "点头之交", 8});

        mData.add(Arrays.asList(
                new HashMap<String, Object>() {{
                    put("name", "总监1");
                    put("desc", "总监");
                    put("size", "100");
                    put("color", "#ABCDEF");
                }},
                new HashMap<String, Object>() {{
                    put("name", "主管1");
                    put("desc", "主管");
                    put("size", "90");
                    put("color", "#FF6666");
                }},
                new HashMap<String, Object>() {{
                    put("name", "主管2");
                    put("desc", "主管");
                    put("size", "90");
                    put("color", "#003366");
                }},
                new HashMap<String, Object>() {{
                    put("name", "员工1");
                    put("desc", "员工");
                    put("size", "80");
                    put("color", "#FF9933");
                }},
                new HashMap<String, Object>() {{
                    put("name", "员工2");
                    put("desc", "员工");
                    put("size", "80");
                    put("color", "#CCCC33");
                }},
                new HashMap<String, Object>() {{
                    put("name", "员工3");
                    put("desc", "员工");
                    put("size", "80");
                    put("color", "#99CCFF");
                }}));
        mData.add(Arrays.asList(
                new HashMap<String, Object>() {{
                    put("value", "");
                    put("width", 10);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 10);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 10);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 10);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 10);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 10);
                }}));
        mData.add(Arrays.asList(
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", "");
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }}));
        mData.add(Arrays.asList(
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", "");
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }}));
        mData.add(Arrays.asList(
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", "");
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }}));
        mData.add(Arrays.asList(
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", "");
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }}));
        mData.add(Arrays.asList(
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", 10);
                    put("width", 2);
                }},
                new HashMap<String, Object>() {{
                    put("value", "");
                    put("width", 2);
                }}));
    }*/

    public GraphChartsBuilder(String type) {
        super(type);
    }

    @Override
    protected void setSeries(Option option, String name, JsonArray data) {
        super.setSeries(option, name, data);
    }

    @Override
    public void build(ECharts charts, ComponentHandler dataHandler) {
        if (DEBUG) {
            /*if (dataHandler == null) {
                createModel(charts, mUserData, mRelativeData);
            }*/
            charts.setData(mData);
            buildData(charts);
            return;
        }
        if (charts.getData() != null) {
            buildData(charts);
        } else if (dataHandler == null) {
            build(charts.getOption(), getTemplate(charts.getTemplate()), true);
        } else if (charts.getQuery() != null) {
            // 要求：传递两条sql，第一条是角色表内容，第二条是关系表内容，两条sql之间以 ";" 分隔
            // 新增要求： 可选传递二至四条语句，其中前两条为sql，第三条为节点大小自定义权重，第四条为线条宽度自定义权重
            String[] splitSQL = ((String) charts.getQuery()).split(";");
            if (splitSQL.length < 2) {
                return;
            }
            List<Object[]> userData = dataHandler.selectList0(Object[].class, charts.getDbId(), splitSQL[0]);
            List<Object[]> relativeData = dataHandler.selectList0(Object[].class, charts.getDbId(), splitSQL[1]);
            if (splitSQL.length == 3) {
                createModel(charts, userData, relativeData, splitSQL[2]);
            } else if (splitSQL.length == 4) {
                createModel(charts, userData, relativeData, splitSQL[2], splitSQL[3]);
            } else {
                createModel(charts, userData, relativeData);
            }
        } else {
            createModel(charts, Collections.emptyList(), Collections.emptyList());
        }
    }

    /**
     * data内容处理
     * data是二维数组，格式如下
     * [
     * ["80,0.5","2,0.3"] (可选，表示基本节点尺寸、尺寸权值、基本线条宽度、宽度权值，可填一至四项)
     * [{name:"祁同伟",desc="省公安厅长",size=80,color="#ABCDEF",category="反面人物"},
     {name="高育良",desc="政法委书记",size=80,color="#BCDEFA",category="反面人物"}, ..., {}],
     * [{value:"0",color=source},{value:"学生",color=source}, ..., {}],
     * ]
     * （可选）其中第一行是尺寸权重，依照节点基本大小和权重计算按线条值计算节点尺寸
     * 第二行是Map列表，存放所有人员信息，包括名字：name、描述：desc、节点尺寸：size（设置节点权值后不生效）、节点颜色：color
     * 第三行开始是关系矩阵，存放所有关系连线，包括关系：value、线条宽度：width（设置宽度权值后不生效）
     * 该方法会将矩阵转化为关系，构建关系图所需的数据格式
     */
    private void buildData(ECharts charts) {
        if (!(charts.getData() instanceof List)
                || ((List) charts.getData()).isEmpty()) {
            return;
        }

        List<List<Object>> dataList = (List<List<Object>>) charts.getData();
        List<Map<String, Object>> personList = new ArrayList<>();
        List<Map<String, Object>> linksList = new ArrayList<>();

        double size = -1;
        double sizeWeight = -1;
        double minSize = -1;
        double maxSize = -1;
        double sum = 0;
        double currentWidth = 0;
        boolean hasWeight = false; // 是否带权值数据
        boolean hasNumber = false; // 所有线条中是否有数字
        boolean isNone = false; // 是否是无箭头
        boolean isDouble = false; // 是否是双向箭头

        typeList = new ArrayList<>();
        List<Object> firstRow = dataList.get(0); // 第一行
        if (firstRow.get(0) instanceof String) { // 存在自定义权值
            String[] sizeGroup = ((String) firstRow.get(0)).split(",");
            if (sizeGroup.length > 1) { // 说明自定义size和自定义权重均有
                size = Double.parseDouble(sizeGroup[0]);
                sizeWeight = Double.parseDouble(sizeGroup[1]);
            } else {
                double baseValue = Double.parseDouble(sizeGroup[0]);
                if (baseValue < 1.0) { // 说明是权值
                    size = 80.0; // 默认尺寸为80
                    sizeWeight = baseValue;
                } else { // 说明是size
                    size = baseValue;
                    sizeWeight = 0.5; // 默认权值为0.5
                }
            }
            hasWeight = true;
        }
        if (hasWeight) { // 如果带有权值数据，从第二行开始解析数据
            firstRow = dataList.get(1);
        }
        // 解析数据
        for (int i = 0; i < firstRow.size(); i++) {
            Map<String, Object> personData = (Map<String, Object>) firstRow.get(i);
            Map<String, Object> person = new LinkedHashMap<>();
            person.put("name", personData.get("name"));
            // 解析矩阵
            // 第 i+1 行就是第一行第 i 个人的关系列表
            // 第一行是权值数据的话，第 i+2 行才是关系列表
            List<Object> linkRow;
            if (hasWeight) {
                linkRow = dataList.get(i + 2);
            } else {
                linkRow = dataList.get(i + 1);
            }
            for (int j = 0; j < linkRow.size(); j++) {
                Map<String, Object> linkData = (Map<String, Object>) linkRow.get(j);
                Map<String, Object> link = new LinkedHashMap<>();
                // 自己与自己没有关系线条
                if (i != j) {
                    link.put("source", personData.get("name"));
                    link.put("target", ((Map<String, Object>) firstRow.get(j)).get("name"));
                    link.put("value", linkData.get("value"));
                    if (linkData.get("value") != null && linkData.get("value") instanceof Number) { // 存在单向和双向线条情况
                        currentWidth = Double.parseDouble(linkData.get("value").toString());
                        if (currentWidth == 0) { // 线条值为零说明不应有线条
                            continue;
                        } else if (linkData.get("noNeedLine") != null
                                && (boolean) linkData.get("noNeedLine")) {
                            continue;
                        }
                        if (i < j) { // 判断对面是否存在线条，若存在则设置双向线条
                            Map<String, Object> resultMap = checkTwoSideByRow(hasWeight, dataList, i, j, false);
                            int result = (int) resultMap.get("result");
                            if (result == 0) {
                                isDouble = false;
                            } else if (result == 1) {
                                isDouble = true;
                                link.put("sourceValue", currentWidth);
                                link.put("targetValue", resultMap.get("value"));
                                link.put("value", currentWidth +
                                        Double.parseDouble(resultMap.get("value").toString()));
                            } else if (result == 3) {
                                isDouble = true;
                                link.put("sourceValue", currentWidth);
                                link.put("targetValue", resultMap.get("value"));
                            }
                        } else {
                            isDouble = false;
                        }
                        sum += currentWidth;
                        hasNumber = true;
                        isNone = false;
                    } else if (linkData.get("value") == null || "".equals(linkData.get("value"))) { // 存在无箭头线条情况
                        isNone = true;
                        isDouble = false;
                        // 判断对面是否存在线条，若存在则此线条可不存
                        Map<String, Object> resultMap = checkTwoSideByRow(hasWeight, dataList, i, j, true);
                        int result = (int) resultMap.get("result");
                        if ((result == 2 && i < j) || result == 1 || result == 3) {
                            continue;
                        }
                    } else if (linkData.get("value") != null && linkData.get("value") instanceof String) {
                        if (linkData.get("noNeedLine") != null
                                && (boolean) linkData.get("noNeedLine")) {
                            continue;
                        }
                        if (i < j) { // 判断对面是否存在线条，若存在则设置双向线条
                            Map<String, Object> resultMap = checkTwoSideByRow(hasWeight, dataList, i, j, false);
                            int result = (int) resultMap.get("result");
                            if (result == 0 || result == 2) {
                                isDouble = false;
                            } else if (result == 1) {
                                isDouble = true;
                                link.put("sourceValue", linkData.get("value"));
                                link.put("targetValue", resultMap.get("value"));
                                link.put("value", resultMap.get("value"));
                            } else if (result == 3) {
                                isDouble = true;
                                link.put("sourceValue", linkData.get("value"));
                                link.put("targetValue", resultMap.get("value"));
                            }
                        } else {
                            isDouble = false;
                        }
                        isNone = false;
                    }
                    if (isNone) { // 无箭头
                        List<Object> symbolType = Arrays.asList("none", "none");
                        link.put("symbol", symbolType);
                    } else if (isDouble) { // 双向箭头
                        List<Object> symbolType = Arrays.asList("arrow", "arrow");
                        link.put("symbol", symbolType);
                    }
                    // 线条颜色
                    Map<String, Object> lineStyle = new HashMap<>();
                    if (linkData.get("color") != null) {
                        if ("source".equals(linkData.get("color").toString())) {
                            lineStyle.put("color", personData.get("color"));
                        } else if ("target".equals(linkData.get("color").toString())) {
                            lineStyle.put("color", ((Map<String, Object>) firstRow.get(j)).get("color"));
                        } else {
                            lineStyle.put("color", linkData.get("color"));
                        }
                    }
                    link.put("lineStyle", lineStyle);
                    linksList.add(link);
                }
            }
            if (hasNumber && size != -1 && sizeWeight != -1) { // 存在自定义权值，准备做计算
                // 寻找最大最小值
                if (i == 0) {
                    minSize = sum;
                    maxSize = sum;
                } else {
                    minSize = Math.min(minSize, sum);
                    maxSize = Math.max(maxSize, sum);
                }
                person.put("symbolSize", sum);
                person.put("hasNumber", true);
            } else if (personData.get("size") != null) { // 存在传入节点大小数据，直接赋予
                person.put("symbolSize", personData.get("size"));
            } else if (hasNumber && size == -1 && sizeWeight == -1) { // 不存在自定义权值，直接设置总权值为节点大小
                person.put("symbolSize", sum);
            }
            // 以下数据为空也不影响图形渲染
            person.put("value", personData.get("desc"));
            Map<String, Object> itemStyle = new HashMap<>();
            itemStyle.put("color", personData.get("color"));
            person.put("itemStyle", itemStyle);
            if (personData.get("category") != null) {
                person.put("category", personData.get("category"));
                if (!typeList.contains(personData.get("category").toString())) {
                    typeList.add(personData.get("category").toString());
                }
            }
            personList.add(person);
            sum = 0;
        }
        /*
        计算节点大小
         */
        if (hasNumber && size != -1 && sizeWeight != -1) {
            for (Map<String, Object> map : personList) {
                double symbolSize;
                if (map.get("hasNumber") != null) {
                    symbolSize = (double) map.get("symbolSize");
                    map.remove("hasNumber");
                } else {
                    continue;
                }
                //System.out.println(map.get("name") + ":" + symbolSize);
                /*
                此处公式为：
                若为总权重最小，则尺寸设置为 基本尺寸 * (1 - 权值)，即最小尺寸
                若为最大，则尺寸设置为 基本尺寸 * (1 + 权值)，即最大尺寸
                若为其他，则尺寸设置为 最小尺寸 + 最大最小尺寸之差 * 总权重所占比例
                 */
                if (minSize == maxSize) {
                    symbolSize = size;
                } else if (symbolSize == minSize) {
                    symbolSize = size * (1 - sizeWeight);
                } else if (symbolSize == maxSize) {
                    symbolSize = size * (1 + sizeWeight);
                } else {
                    symbolSize = size * (1 - sizeWeight) + (symbolSize - minSize) / (maxSize - minSize) * 2 * size * sizeWeight;
                }
                map.put("symbolSize", symbolSize);
            }
        }
        /*
        设置Series
         */
        if (!personList.isEmpty()) {
            if (charts.getOption().getSeries() instanceof Map) {
                Map<String, Object> graph = (Map<String, Object>) charts.getOption().getSeries();
                graph.put("data", personList);
                graph.put("links", linksList);
                if (typeList != null && !typeList.isEmpty()) {
                    List<Map<String, String>> categories = new ArrayList<>();
                    for (Object type : typeList) {
                        Map<String, String> category = new HashMap<>();
                        category.put("name", type.toString());
                        categories.add(category);
                    }
                    graph.put("categories", categories);
                }
            }
            // Series以List方式存在（主要）
            else if (charts.getOption().getSeries() instanceof List) {
                List<Map<String, Object>> seriesList = (List) charts.getOption().getSeries();
                if (seriesList.size() == 1) {  // Series列表里只有一条数据
                    // 设置这一条的数据
                    Map<String, Object> graph = seriesList.get(0);
                    graph.put("data", personList);
                    graph.put("links", linksList);
                    if (typeList != null && !typeList.isEmpty()) {
                        List<Map<String, String>> categories = new ArrayList<>();
                        for (Object type : typeList) {
                            Map<String, String> category = new HashMap<>();
                            category.put("name", type.toString());
                            categories.add(category);
                        }
                        graph.put("categories", categories);
                    }
                    seriesList.set(0, graph);
                } else {  // Series列表里有多条数据
                    // 暂待实现
                }
            }
        }
    }

    /**
     * 判断矩阵对面的线条是否存在
     * 对面线条：0：不存在  1：数字  2、空字符  3：字符串
     */
    private Map<String, Object> checkTwoSideByRow(boolean hasWeight, List<List<Object>> dataList,
                                                  int i, int j, boolean isNone) {
        Map<String, Object> result = new HashMap<>();
        List<Object> personList;
        if (hasWeight) {
            personList = dataList.get(j + 2);
        } else {
            personList = dataList.get(j + 1);
        }
        Map<String, Object> map = (Map<String, Object>) personList.get(i);
        if (map.get("value") != null && map.get("value") instanceof Number) {
            if (Double.parseDouble(map.get("value").toString()) != 0) {
                result.put("result", 1);
                result.put("value", Double.parseDouble(map.get("value").toString()));
                if (!isNone) { // 这边不为空，才不需要这条线
                    map.put("noNeedLine", true);
                }
            } else {
                result.put("result", 0);
            }
        } else if (map.get("value") == null || "".equals(map.get("value"))) {
            result.put("result", 2);
        } else if (map.get("value") != null && map.get("value") instanceof String) {
            result.put("result", 3);
            result.put("value", map.get("value"));
            if (!isNone) { // 这边不为空，才不需要这条线
                map.put("noNeedLine", true);
            }
        }
        return result;
    }

    private void createModel(ECharts charts, List<Object[]> userData, List<Object[]> relativeData, String... weight) {
        double baseSize = -1;
        double baseSizeWeight = -1;
        if (weight.length > 0) { // 说明存在自定义权重
            String[] sizeWeight = weight[0].split(",");
            if (sizeWeight.length > 1) { // 说明自定义size和自定义权重均有
                baseSize = Double.parseDouble(sizeWeight[0]);
                baseSizeWeight = Double.parseDouble(sizeWeight[1]);
            } else {
                double baseValue = Double.parseDouble(sizeWeight[0]);
                if (baseValue < 1.0) { // 说明是权值
                    baseSize = 80.0; // 默认尺寸为80
                    baseSizeWeight = baseValue;
                } else { // 说明是size
                    baseSize = baseValue;
                    baseSizeWeight = 0.5; // 默认权值为0.5
                }
            }
        }
        setSeriesContent(charts, userData, relativeData, baseSize, baseSizeWeight);
    }

    /**
     * 设置Series内容
     */
    private void setSeriesContent(ECharts charts, List<Object[]> userData, List<Object[]> relativeData,
                                  double size, double sizeWeight) {
        // Series以Map方式存在
        if (charts.getOption().getSeries() instanceof Map) {
            Map<String, Object> graph = (Map<String, Object>) charts.getOption().getSeries();
            graph.put("data", formatUserData(userData, relativeData, size, sizeWeight));
            graph.put("links", formatRelativeData(userData, relativeData));
            if (typeList != null && !typeList.isEmpty()) {
                List<Map<String, String>> categories = new ArrayList<>();
                for (Object type : typeList) {
                    Map<String, String> category = new HashMap<>();
                    category.put("name", type.toString());
                    categories.add(category);
                }
                graph.put("categories", categories);
            }
        }
        // Series以List方式存在（主要）
        else if (charts.getOption().getSeries() instanceof List) {
            List<Map<String, Object>> seriesList = (List) charts.getOption().getSeries();
            if (seriesList.size() == 1) {  // Series列表里只有一条数据
                // 设置这一条的数据
                Map<String, Object> graph = seriesList.get(0);
                graph.put("data", formatUserData(userData, relativeData, size, sizeWeight));
                graph.put("links", formatRelativeData(userData, relativeData));
                if (typeList != null && !typeList.isEmpty()) {
                    List<Map<String, String>> categories = new ArrayList<>();
                    for (Object type : typeList) {
                        Map<String, String> category = new HashMap<>();
                        category.put("name", type.toString());
                        categories.add(category);
                    }
                    graph.put("categories", categories);
                }
                seriesList.set(0, graph);
            } else {  // Series列表里有多条数据
                // 暂待实现
            }
        }
    }

    /**
     * 将角色信息格式化
     */
    private List<Map<String, Object>> formatUserData(List<Object[]> userData, List<Object[]> relativeData,
                                                     double size, double sizeWeight) {
        // 空数据处理
        if (userData == null || userData.size() <= 0) {
            List<Map<String, Object>> emptyData = new ArrayList<>();
            Map<String, Object> emptyMap = new HashMap<>();
            emptyMap.put("name", "暂无数据");
            emptyData.add(emptyMap);
            return emptyData;
        }
        List<Map<String, Object>> data = new ArrayList<>();
        typeList = new ArrayList<>();
        boolean isNumber = false; // 判断关系value是字符还是权值
        double sizeSum = 0; // 某人关系的总权值
        double min = -1; // 最小值
        double max = -1; // 最大值
        for (int i = 0; i < userData.size(); i++) {
            Object[] userDatum = userData.get(i);
            Map<String, Object> dataVariable = new HashMap<>();
            dataVariable.put("name", userDatum[0]);
            if (userDatum.length > 1) {
                dataVariable.put("value", userDatum[1]);
            }
            if (userDatum.length > 2) {
                dataVariable.put("category", userDatum[2]);
                if (!typeList.contains(userDatum[2].toString())) {
                    typeList.add(userDatum[2].toString());
                }
            }
            if (userDatum.length > 3) {
                Map<String, Object> colorMap = new HashMap<>();
                colorMap.put("color", userDatum[3]);
                dataVariable.put("itemStyle", colorMap);
            }
            /*
            计算节点大小做准备
             */
            for (Object[] relativeDatum : relativeData) {
                // 遍历所有以当前人员为起点的关系
                if (userDatum[0].equals(relativeDatum[0])) {
                    // 此处必须为数字类型，否则权重计算无意义
                    if (relativeDatum[2] instanceof Number) {
                        sizeSum += Double.parseDouble(relativeDatum[2].toString());
                        isNumber = true;
                    }
                }
            }
            if (isNumber && size != -1 && sizeWeight != -1) { // 存在自定义权值，准备做计算
                // 寻找最大最小值
                if (i == 0) {
                    min = sizeSum;
                    max = sizeSum;
                } else {
                    if (sizeSum < min) {
                        min = sizeSum;
                    } else if (sizeSum > max) {
                        max = sizeSum;
                    }
                }
                dataVariable.put("symbolSize", sizeSum);
                dataVariable.put("hasNumber", true);
            } else if (userDatum.length > 4) { // 存在传入节点大小数据，直接赋予
                dataVariable.put("symbolSize", userDatum[4]);
            } else if (isNumber && size == -1 && sizeWeight == -1) { // 不存在自定义权值，直接设置总权值为节点大小
                dataVariable.put("symbolSize", sizeSum);
            }
            data.add(dataVariable);
            sizeSum = 0;
        }

        /*
        计算节点大小
         */
        if (isNumber && size != -1 && sizeWeight != -1) {
            for (Map<String, Object> map : data) {
                double symbolSize;
                if (map.get("hasNumber") != null) {
                    symbolSize = (double) map.get("symbolSize");
                    map.remove("hasNumber");
                } else {
                    continue;
                }
                /*
                此处公式为：
                若最小权重等于最大权重，说明所有节点一样大，设置为基本尺寸
                若为总权重最小，则尺寸设置为 基本尺寸 * (1 - 权值)，即最小尺寸
                若为最大，则尺寸设置为 基本尺寸 * (1 + 权值)，即最大尺寸
                若为其他，则尺寸设置为 最小尺寸 + 最大最小尺寸之差 * 总权重所占比例
                 */
                if (min == max) {
                    symbolSize = size;
                } else if (symbolSize == min) {
                    symbolSize = size * (1 - sizeWeight);
                } else if (symbolSize == max) {
                    symbolSize = size * (1 + sizeWeight);
                } else {
                    symbolSize = size * (1 - sizeWeight) + (symbolSize - min) / (max - min) * 2 * size * sizeWeight;
                }
                map.put("symbolSize", symbolSize);
            }
        }
        return data;
    }

    /**
     * 将关系矩阵格式化
     */
    private List<Map<String, Object>> formatRelativeData(List<Object[]> userData, List<Object[]> relativeData) {
        // 空处理
        if (relativeData == null || relativeData.size() <= 0) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> links = new ArrayList<>();
        boolean isNone = false;
        boolean isDouble = false;
        for (int i = 0; i < relativeData.size(); i++) {
            Object[] relativeDatum = relativeData.get(i);
            Map<String, Object> dataVariable = new HashMap<>();
            dataVariable.put("source", relativeDatum[0]);
            dataVariable.put("target", relativeDatum[1]);
            if (relativeDatum.length > 2) {
                dataVariable.put("value", relativeDatum[2]);
                Map<String, Object> resultMap = checkTwoSide(relativeData,
                        relativeDatum[0].toString(), relativeDatum[1].toString());
                int result = (int) resultMap.get("result");
                if (relativeDatum[2] != null && relativeDatum[2] instanceof Number) {
                    double currentWidth = Double.parseDouble(relativeDatum[2].toString());
                    if (currentWidth == 0) { // 权重为零说明不存在线条
                        continue;
                    } else {
                        if (result == 0 || result == 2) {
                            isDouble = false;
                        } else if (result == 1) {
                            isDouble = true;
                            dataVariable.put("value", currentWidth
                                    + Double.parseDouble(resultMap.get("value").toString()));
                            dataVariable.put("sourceValue", currentWidth);
                            dataVariable.put("targetValue", resultMap.get("value"));
                        } else if (result == 3) {
                            isDouble = true;
                            dataVariable.put("sourceValue", currentWidth);
                            dataVariable.put("targetValue", resultMap.get("value"));
                        }
                    }
                    isNone = false;
                } else if (relativeDatum[2] == null || "".equals(relativeDatum[2])) {
                    isNone = true;
                    isDouble = false;
                    if (result == 1 || result == 3) {
                        continue;
                    }
                } else if (relativeDatum[2] instanceof String) {
                    if (result == 0 || result == 2) {
                        isDouble = false;
                    } else if (result == 1) {
                        isDouble = true;
                        dataVariable.put("value",
                                Double.parseDouble(resultMap.get("value").toString()));
                        dataVariable.put("sourceValue", relativeDatum[2]);
                        dataVariable.put("targetValue", resultMap.get("value"));
                    } else if (result == 3) {
                        isDouble = true;
                        dataVariable.put("sourceValue", relativeDatum[2]);
                        dataVariable.put("targetValue", resultMap.get("value"));
                        isNone = false;
                    }
                }
            }
            if (isNone) { // 无箭头
                List<Object> symbolType = Arrays.asList("none", "none");
                dataVariable.put("symbol", symbolType);
            } else if (isDouble) { // 双向箭头
                List<Object> symbolType = Arrays.asList("arrow", "arrow");
                dataVariable.put("symbol", symbolType);
            }
            // 线条颜色
            if (relativeDatum.length > 3 && relativeDatum[3] != null && !"".equals(relativeDatum[3])) {
                Map<String, Object> lineStyle = new HashMap<>();
                if ("source".equals(relativeDatum[3].toString())) {
                    if (findItemColor(userData, relativeDatum[0].toString()) != null) {
                        lineStyle.put("color", findItemColor(userData, relativeDatum[0].toString()));
                    }
                } else if ("target".equals(relativeDatum[3].toString())) {
                    if (findItemColor(userData, relativeDatum[0].toString()) != null) {
                        lineStyle.put("color", findItemColor(userData, relativeDatum[1].toString()));
                    }
                } else {
                    lineStyle.put("color", relativeDatum[3]);
                }
                dataVariable.put("lineStyle", lineStyle);
            }
            links.add(dataVariable);
        }
        return links;
    }

    /**
     * 是否存在双向线条
     */
    private Map<String, Object> checkTwoSide(List<Object[]> relativeData, String source, String target) {
        Map<String, Object> result = new HashMap<>();
        result.put("result", 0);
        for (Object[] datum : relativeData) {
            if (source.equals(datum[1]) && target.equals(datum[0])) {
                if (datum.length > 2) {
                    if (datum[2] instanceof Number) {
                        if (Double.parseDouble(datum[2].toString()) != 0) {
                            result.put("result", 1);
                            result.put("value", Double.parseDouble(datum[2].toString()));
                        } else {
                            result.put("result", 0);
                        }
                    } else if (datum[2] instanceof String) {
                        if ("".equals(datum[2].toString())) {
                            result.put("result", 2);
                        } else {
                            result.put("result", 3);
                            result.put("value", datum[2].toString());
                        }
                    } else if (datum[2] == null) {
                        result.put("result", 2);
                    }
                } else {
                    result.put("result", 2);
                }
            }
        }
        return result;
    }

    private String findItemColor(List<Object[]> userData, String name) {
        for (Object[] userDatum : userData) {
            if (name.equals(userDatum[0])) {
                if (userDatum.length > 2 && userDatum[2] != null && !"".equals(userDatum[2])) {
                    return userDatum[2].toString();
                } else {
                    break;
                }
            }
        }
        return null;
    }
}
